import scrapy
from selenium import webdriver
import time
from scrapy.http import Request
from selenium.webdriver.common.action_chains import ActionChains


class CrawldoubanSpider(scrapy.Spider):
    name = 'crawldouban'
    allowed_domains = ['douban.com']

    # 这是一个框架，会自动执行爬取,直接爬取被禁止访问403，需要模拟浏览器，所以下面注释掉, 重写父类strat_request方法
    # start_urls = ['http://douban.com/'] # 爬取页面后会自动调用parse

    def get_tracks(self,distance):
        """  拿到移动轨迹，模仿人的滑动行为，先匀加速后匀减速
        匀变速运动基本公式：
        ①v = v0+at ②s = v0t+1/2at^2
        """
        v = 0  # 初速度
        t = 0.31  # 单位时间为0.3s来统计轨迹，轨迹即0.3内的位移
        tracks = []  # 位置/轨迹列表，列表内的一个元素代表0.3s的位移
        current = 0  # 当前位移
        mid = distance * 4 / 5  # 到达mid值开始减速
        while current < distance:
            if current < mid:
                a = 2  # 加速度越小，单位时间内的位移越小，模拟的轨迹就越多越详细
            else:
                a = -3
            v0 = v  # 初速度
            s = v0 * t + 0.5 * a * (t ** 2)  # 0.3秒内的位移
            current += s  # 当前的位置
            tracks.append(round(s))  # 添加到轨迹列表
            v = v0 + a * t  # 速度已经到达v,该速度作为下次的初速度
        return tracks

    def start_requests(self):  # 重写父类方法，这个方法也会自动执行，不过需要手动调用parse方法
        # 构造chrome请求头
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36"}
        # 构造请求
        url = "https://douban.com/"
        request_url = Request(url=url, headers=headers, callback=self.parse) # Request中url是必须的
        return [request_url]

    def parse(self, response):
        # 浏览器使用配置，防止使用selenium被检测到

        # options = webdriver.ChromeOptions()  # 浏览器使用配置，防止使用selenium被检测到
        # 告诉目标网址，这个是一个浏览器，因为有本地用户浏览数据
        # options.add_argument(r'--user-data-dir=G:\projects\PycharmProjects\User Data')
        # google_driver = "D:\Installation_Package\chromedriver_win32\chromedriver.exe"
        # browser = webdriver.Chrome(executable_path=google_driver, options=options)
        profile_path = r"C:\Users\fc\AppData\Roaming\Mozilla\Firefox\Profiles\721de3k0.default-release"
        firefox_profile=webdriver.FirefoxProfile(profile_path)
        browser=webdriver.Firefox(firefox_profile=firefox_profile)

        browser.get("https://www.douban.com")  #开始请求
        browser.switch_to.frame(0)  # 传入id属性或者网址，一般传id,0代表第一个fram
        pwd_login = browser.find_element_by_xpath("//li[@class='account-tab-account']")  # 元素定位
        pwd_login.click()  # 模拟点击，这里会报错，因为密码登录在iframe中,需要进入子界面才能定位到元素
        browser.find_element_by_xpath("//*[@id='username']").send_keys("18768788978")
        browser.find_element_by_xpath("//*[@id='password']").send_keys("FC18768788978")
        browser.find_element_by_xpath(
            "//div[@class='account-form-field-submit ']/a[@class='btn btn-account btn-active']").click()
        time.sleep(4)
        auth_frame = browser.find_element_by_id('tcaptcha_iframe')
        browser.switch_to.frame(auth_frame)
        # 滑动验证码破解
        slip = browser.find_element_by_xpath("//*[@id='tcaptcha_drag_thumb']")
        ActionChains(browser).click_and_hold(on_element=slip).perform()  # 点击并保持点击
        ActionChains(browser).move_to_element_with_offset(to_element=slip, xoffset=180, yoffset=0).perform()

        tracks = self.get_tracks(25)
        for track in tracks:
            ActionChains(browser).move_by_offset(xoffset=track, yoffset=0).perform()  # 开始移动move_by_offset()
        time.sleep(0.5)
        ActionChains(browser).release().perform()  # 登录已经攻破 ,跳转到新的页面
        time.sleep(1)  # 线程睡眠，等待页面加载
        browser.refresh()  # 页面刷新一下，否则无法获取新页面数据
        data = browser.page_source  # 获取当前页面数据
        print(str(data)) # 登录失败，可数据却得到了
